package org.example.web;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.example.result.ResultData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static org.example.constant.RedisConstant.*;
import static org.example.constant.ExcludePath.EXCLUDEPATH;

/**
 * 用户鉴权
 */
@Slf4j
@Order(-1)
@Component
public class AuthFilter implements GlobalFilter {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //对指定路径进行放行
        List<String> releasePath = Arrays.asList(EXCLUDEPATH);
        //请求路径
        final String path = exchange.getRequest().getURI().getPath();
        log.info("请求路径为：" + path);
        boolean off = false;
        for (String uri : releasePath) {
            if (uri.equals(path)) {
                off = true;
                break;
            }
        }
        //如果有指定放行的请求路径则进行放行
        if (off) {
            return chain.filter(exchange);
        }
        //获取token
        String token = exchange.getRequest().getHeaders().getFirst("token");
        log.info("登录token为：" + token);
        //如果token为空则进行拦截
        if (StringUtils.isEmpty(token)) {
            return interceptMsg(exchange);
        }
        //解析token,获取用户id
        final JWT jwt;
        try {
            jwt = JWTUtil.parseToken(token);
        } catch (Exception e) {
            //出现异常说明携带的信息解析失败，进行拦截
            return interceptMsg(exchange);
        }
        Object data = jwt.getPayload(TOKEN_UUID);
        //解析的数据为null，则进行拦截
        if (data == null) {
            return interceptMsg(exchange);
        }
        String tokenUUID = String.valueOf(data);
        //判断和缓存里面的token是否一致
        String redisToken = redisTemplate.opsForValue().get(LOGIN_TOKEN + tokenUUID);
        //缓存中没有数据，说明登录过期，进行拦截
        if (redisToken == null || "".equals(redisToken)) {
            return interceptMsg(exchange);
        }
        //判断两个token是否一致，拦截
        if (!token.equals(redisToken)) {
            return interceptMsg(exchange);
        }
        //刷新token缓存过期时间
        redisTemplate.expire(LOGIN_TOKEN + tokenUUID, TOKEN_EXPIRE_TIME, TimeUnit.MINUTES);
        //刷新用户缓存时间
//        redisTemplate.expire(USER_LOGIN + userId, USER_EXPIRE_TIME, TimeUnit.MINUTES);
        //放行
        return chain.filter(exchange);
    }


    /**
     * 返回拦截信息
     */
    private Mono<Void> interceptMsg(ServerWebExchange exchange) {
        //拦截信息
        String errorResponse = JSONObject.toJSONString(ResultData.authFail());
        //返回格式未json
        exchange.getResponse().getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(errorResponse.getBytes())));
    }
}
